import React, {FC, useCallback, useEffect, useMemo, useRef, useState} from "react";
import "./css/SelectForm.less";
import {TreeSelect} from "antd";
import {getObjByRule, isArray, isString, treeFilterMap, treeMap} from "../../utils";
import useStateRef from "../../customUse/useStateRef.tsx";
import useDebounce from "../../customUse/useDebounce.tsx";
import {AxiosGet} from "../../services/HttpService.tsx";
import Config from "../../Config.tsx";
import { getLocale } from "../../../i18n/i18n.tsx";

interface SelectTreeFormProps {
    menuId: string,
    mode: string,
    value?: any,
    url: string,
    params: any,
    id: string,
    format: any,
    showSearch: boolean,
    allowClear: boolean,
    disabled: boolean,
    options?: any[],
    onChange: Function,
    labelKey?: string | undefined,
    valueKey?: string | undefined,
    joinKey?: string,
    isAddSearchValue?: boolean
}

const SelectTreeForm: FC<SelectTreeFormProps> = (props) => {

    const selectOptionRef = useRef();
    const allSelectOptionRef = useRef<any[]>();

    const [selectOption, setSelectOption] = useStateRef([], selectOptionRef),
        [value, setValue] = useState<any>(undefined);

    const loadOption = useCallback(async () => {
        const {
            format = {
                id: "id",
                value: "id",
                label: "zhCn|usEn|ptBr"
            }, params = {}
        }: { format: any, params: any } = props;
        let options: any[] = [];

        if (props.url) {
            const {data = []}: { data: any[] } = await AxiosGet(props.url, {
                ...params,
                [Config.axiosSerMenuKey]: props.menuId
            });
            options = treeMap(data, (child: any[], node: any) => {
                let item: any = getObjByRule(node, {id: "id", value: "id", label: "zhCn|usEn|ptBr", ...format}, true);
                return {
                    ...item,
                    children: child ? child : null
                }
            })
        } else if (props.options) {
            options = props.options || [];
        }
        if(!options.length) {
            let {labelKey = "label", valueKey = "value", ds = {}}: {
                labelKey: string,
                valueKey: string,
                isAddSearchValue: boolean
            } = props;
            options = [{[labelKey]: getLocale(ds.zh, ds.en), [valueKey]: ds.value}]
        }
        setSelectOption(options);
        allSelectOptionRef.current = options;
    }, [props.options, props.url, props.params, props.menuId]);

    useEffect(() => {
        loadOption();
    }, [props.options, props.url, props.params]);

    useEffect(() => {
        const {ds = {}}: { ds: any } = props;
        let newValue = ds.value || props.value;
        if (newValue) {
            if (["multiple", "tags"].indexOf(props.mode) === -1 && isString(newValue)) {
                const {joinKey = ","}: { joinKey: string } = props;
                setValue(isString(newValue) ? newValue.split(joinKey) : newValue);
            } else {
                setValue(newValue);
            }
        }
    }, [props.ds, props.mode]);

    const handelChange: Function = useCallback((value: any) => {
        const {joinKey}: { joinKey: string } = props;
        setValue(value);
        props.onChange && props.onChange(isArray(value) && joinKey ? value.join(joinKey) : (value || ""));
    }, [props.onChange, props.joinKey]);


    const handelSearch: Function = useDebounce((text: string) => {
        const {labelKey = "label", valueKey = "value", isAddSearchValue = false}: {
            labelKey: string,
            valueKey: string,
            isAddSearchValue: boolean
        } = props;

        let newSelectOption: any[] = treeFilterMap(allSelectOptionRef.current, (item: any) => {
            return item[labelKey].indexOf(text) !== -1;
        });

        if (isAddSearchValue && !newSelectOption.length) {
            let node: object = {
                [labelKey]: text,
                [valueKey]: text
            }
            newSelectOption.push(node);
        }
        setSelectOption(JSON.parse(JSON.stringify(newSelectOption)));
    }, 500, [selectOption, props.labelKey, props.valueKey, props.isAddSearchValue]);

    const handelClear: Function = useCallback((value: any) => {
        setSelectOption(JSON.parse(JSON.stringify(allSelectOptionRef.current)));
    }, []);

    const renderSelectForm = useMemo(() => {
        if (!selectOptionRef.current) {
            return null
        }

        const {labelKey = "label", valueKey = "value", mode, showSearch = true, allowClear = true}:
            {

                labelKey: string,
                valueKey: string,
                mode: "multiple" | "tags" | undefined,
                showSearch: boolean,
                allowClear: boolean
            } = props;

        const selectProps = {
            popupClassName: "sf_core_select_form_dropdown",
            multiple: mode === "multiple",
            value,
            showSearch,
            treeLine: true,
            disabled: props.disabled,
            allowClear,
            treeDefaultExpandAll: true,
            treeData: selectOption,
            fieldNames: {label: labelKey, value: valueKey},
            filterTreeNode: false,
            onSearch: handelSearch,
            onChange: handelChange,
            onClear: handelClear
        };
        return (
            <div className="sf_core_select_form">
                <TreeSelect
                    {...selectProps}
                />
            </div>
        )
    }, [props, selectOption, value]);

    return (renderSelectForm)
};

export default React.memo(SelectTreeForm);
